package netty.test4Chat;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;

/**
 * 聊天服务器
 * (快捷打出 变量= 的    new String().var)
 */
public class ChatServer {
    private Selector selector;
    private ServerSocketChannel serverSocketChannel;
    private static final int port=8000;

    /**
     * 构造方法里完成初始化
     */
    public ChatServer() {
        try{
            //1,获取 selector
            selector=Selector.open();
            //2, 获取serverChannel
            serverSocketChannel=ServerSocketChannel.open();
            //3,绑定端口
            serverSocketChannel.socket().bind(new InetSocketAddress(port));
            //4,设置非阻塞
            serverSocketChannel.configureBlocking(false);
            //5,将该serverSocketChannel 注册到 selector
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 监听
     */
    public void listen(){
        try{
            while(true){
                //1,循环监听
                int count=selector.select(2000);//这个地方不设置时间也行
                //2，如果count >0 说明有事件就绪
                if(count>0){
                //3,遍历得到的 selectionKey 集合
                    Iterator<SelectionKey> it=selector.selectedKeys().iterator();
                    while(it.hasNext()){
                        //4,取出selectionKey
                        SelectionKey key=it.next();
                        //5,监听连接事件
                        if(key.isAcceptable()){
                            //6,获取socketChannel
                            SocketChannel socket=serverSocketChannel.accept();//这里本来是阻塞的，但是这里不会，因为通道已经就绪
                            socket.configureBlocking(false);
                            //7，将socket 注册到 selector 上
                            socket.register(selector,SelectionKey.OP_READ);
                            System.out.println(socket.getRemoteAddress()+"上线了");
                        }
                        //8,通道发送read 事件，即通道是可读状态
                        if(key.isReadable()){
                        //9，处理读的方法
                            read(key);
                        }

                        //10 处理完成后，要把当前key 删除防止重复处理
                        it.remove();
                    }
                }else{
                   // System.out.println("等待连接");
                }
            }
        }catch (Exception e){

        }
    }

    /**
     * 读取客户端消息
     * @param key
     */
    private void read(SelectionKey key){
        //1，定义一个sockeChannel
        SocketChannel socketChannel=null;
        try{
        //2,取到关联的channel
            socketChannel=(SocketChannel)key.channel();
            //3,创建缓冲
            ByteBuffer buffer=ByteBuffer.allocate(1024);
            //3,从通道中读取数据
            int count=socketChannel.read(buffer);
            //4,count>0 表示读取到数据了
            if(count>0){
            //5，把读取到的数据转为字符串
                String msg = new String(buffer.array());
                //6,输出消息
                System.out.println("客户端发来的消息为:"+msg);
                //7,向其他的客户端转发消息（专门写一个方法）
                sendInfoToOtherClient(msg,socketChannel);
            }
        }catch (IOException e){
            //写一个提示 来提示 连接断开的
            try{
                System.out.println(socketChannel.getRemoteAddress()+"客户端离线了");
                //2,离线后，要关闭通道
                socketChannel.close();
            }catch (Exception e2){
                e.printStackTrace();
            }

        }
    }


    /**
     * 转发消息给其他的客户
     *
     * 注意发消息的时候要排除自己
     * 下面参数的self 就是要排除的（自己）
     */

    private void sendInfoToOtherClient(String msg,SocketChannel self) throws IOException {
        //1，遍历所有注册到 selector上的 socketChannel 并排除自己
        for(SelectionKey key:selector.keys()){
            //2,通过key 取出对应的 socketChannel
            Channel channel = key.channel();
            //3,排除自己
            if(channel instanceof SocketChannel && channel !=self){
                //4,转成socketChannel (在第二步转也行)
                SocketChannel socket=(SocketChannel)channel;
                //5,将msg 存入buffer
                ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
                //6,将buffer的数据写入通道
                socket.write(buffer);
            }
        }
    }


    public static void main(String[] args) {
        //1,创建一个服务器对象
        ChatServer chatServer = new ChatServer();
        //2,监听
        chatServer.listen();
    }
}
